/*
 * Fichier: GenerateArticle.java
 * Crée le: 17 juillet 2007.
 * Modifié: 20 juin 2012.
 * Auteurs: Sébastien ESTIENNE.
 * SiteWeb: http://www.prog-info.org/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package generator.applet;



import java.awt.Dimension;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javaexos.business.Book;
import javaexos.io.XMLFileBook;
import javaexos.model.ChapterModel;
import javaexos.model.ExerciseModel;



/**
 * <p>Génère des fichiers html pour les applets.</p>
 * @author Sébastien ESTIENNE.
 */
public class GenerateHtml
{
   /**
    * <p>Constante chapitre.</p>
    */
   public static final String CHAPITRE = "chapitre";

   /** Les informations du chapitre. */
   private ChapterModel chapter = null;

   /** La taille des fenêtres des applets. */
   private List<Dimension> appletDimension = null;

   /** Le chemin vers le chapitre. */
   private String chapterFilepath = null;
   
   /** Répertoire de sortie où seront produits les fichiers html. */
   private String htmlPath = null;
   
   /** Répertoire vers les fichiers java des exercices. */
   private String exercisesPath = null;

   
   /**
    * <p>Génère les fichiers html des applets pour un chapitre donné.</p>
    * @param chapterFilepath Chemin vers le chapitre au format XML à analyser.
    * @param exercisesPath Répertoire vers les fichiers java des exercices.
    * @param htmlPath Répertoire de sortie où les fichiers jnlp seront produits.
    */
   public GenerateHtml(String chapterFilepath, String exercisesPath, String htmlPath)
   {
      // Initialisation des répertoires.
      this.chapterFilepath = chapterFilepath;
      this.exercisesPath = exercisesPath;
      this.htmlPath = htmlPath;
      
      // Initialisation de la liste des tailles des applets.
      this.appletDimension = new ArrayList<Dimension>();
      
      // Charge le chapitre et récupère les dimensions de l'applet.
      boolean ok = loadData();

      if(ok)
      {
         // Génère les fichiers Jnlp des exercices.
         generateHtml();
      }
   }
   

   /**
    * <p>Construit la structure de données 'chapitre' à partir des données du fichier xml.</p>
    * @return true Si le chapitre a été chargé correctement sinon false.
    */
   private boolean loadData()
   {
      // Transforme le chemin vers le chapitre en URL.
      URL url = null;
      try
      {
         url = new File(this.chapterFilepath).toURI().toURL();
      }
      catch(MalformedURLException e)
      {
         e.printStackTrace();
      }
      
      // Charge le chapitre.
      Book book = new XMLFileBook();
      this.chapter = book.parseChapter(url);
      
      // Récupère les dimensions de l'applet.
      if(this.chapter != null)
      {
         for (ExerciseModel exercise : this.chapter.getExercises())
         {
            this.appletDimension.add(getAppletDimension(exercise));
         }
      }
      // Le chapitre ne s'est pas chargé correctement.
      else
      {
         return false;
      }
      
      return true;
   }
   
   /**
    * Récupère les dimensions de l'applet correspondant à un exercice.
    * @param exercise L'exercice concerné.
    * @return Les dimensions de l'applet correspondant à un exercice.
    */
   public Dimension getAppletDimension(ExerciseModel exercise)
   {
      Dimension result = null;
      
      // Construit le nom du fichier où extraire les informations.
      String filename = this.exercisesPath + exercise.getName() + ".html";
      
      // Expression à rechercher dans le fichier.
      Pattern pattern = Pattern.compile(".*width=\"([0-9]+)\".*height=\"([0-9]+)\".*");

      Scanner scanner = null;
      String width = null;
      String height = null;
      String line = null;
      try
      {
         // Parcours le fichier HTML.
         scanner = new Scanner(new File(filename));
         while(scanner.hasNext())
         {
            line = scanner.nextLine();
            Matcher matcher = pattern.matcher(line);
            // Récupère la largeur et la hauteur.
            if(matcher.find() && matcher.groupCount() == 2)
            {
               width = matcher.group(1);
               height = matcher.group(2);
               break;
            }
         }
      }
      catch (FileNotFoundException e)
      {
         e.printStackTrace();
      }
      finally
      {
         if(scanner != null)
         {
            scanner.close();
         }
      }
      
      // Défini les dimensions de l'applet.
      result = new Dimension(Integer.parseInt(width), Integer.parseInt(height));
      
      return result;
   }


   /**
    * <p>Génère les fichiers html des applets des exercices du chapitre.</p>
    */
   private void generateHtml()
   {
      // Génère les fichires html de chaque exercice.
      List< ? extends ExerciseModel> exercices = this.chapter.getExercises();
      int i = 0;
      for(ExerciseModel exo : exercices)
      {
         // Le chemin du fichier.
         File file = new File(this.htmlPath + exo.getName() + ".php");

         // Pour écrire dans le fichier.
         PrintWriter writer = null;

         // Supprime le fichier s'il existe déjà.
         if(file.exists())
         {
            file.delete();
         }

         // Ecrit l'article.
         try
         {
            // Format decimal de date.
            DecimalFormat dateFormat = new DecimalFormat("00");

            // Création du fichier.
            file.createNewFile();

            writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));

            // En tête du fichier.
            writer.write("<?\n");
            writer.write("$rubrique = 4;\n");
            writer.write("$meta_description = \"Chapitre " + this.chapter.getNumber() + " : "
                  + this.chapter.getTitle() + ", Exercice " + exo.getNumber() + " : "
                  + unescapeHTML(exo.getTitle()) + ".\";\n");
            writer.write("$meta_keywords = \"");
            List<String> keyWords = this.chapter.getKeyWords();
            for(String key : keyWords)
            {
               writer.write(unescapeHTML(key) + ", ");
            }
            writer.write(exo.getName() + "\";\n");
            writer.write("$titre_page = \"Chapitre " + this.chapter.getNumber() + ", Exercice "
                  + exo.getNumber() + " : " + unescapeHTML(exo.getTitle()) + "\";\n");
            writer.write("$xhtml = true;\n");
            writer.write("$Licence = \"1\";\n");
            Calendar creation = this.chapter.getCreation();
            writer.write("$Annee = \"" + creation.get(Calendar.YEAR) + "\";\n");
            writer.write("$dateBrute['date'] = '"
                  + dateFormat.format(creation.get(Calendar.DAY_OF_MONTH)) + "/"
                  + dateFormat.format(creation.get(Calendar.MONTH) + 1) + "/"
                  + dateFormat.format(creation.get(Calendar.YEAR)) + "';\n");
            Calendar today = Calendar.getInstance();
            writer.write("$dateBrute['miseajour'] = '"
                  + dateFormat.format(today.get(Calendar.DAY_OF_MONTH)) + "/"
                  + dateFormat.format(today.get(Calendar.MONTH) + 1) + "/"
                  + today.get(Calendar.YEAR) + "';\n");
            writer.write("$topicType = 'Whitepaper';\n");
            writer.write("$urlCss = \"./xo_css.css\";\n");
            writer.write("\n");
            writer.write("include(\"$DOCUMENT_ROOT/template/entete.php\");\n");
            writer.write("?>\n");
            writer.write("\n");
            
            // Contenu du fichier.
            writer.write("<div id=\"xo_global\">\n");
            writer.write("\n");
            writer.write("    <div id=\"xo_alignement\">\n");
            writer.write("\n");
            writer.write("        <h1><a id=\"page_presentation\"></a>Chapitre "
                  + this.chapter.getNumber() + ", Exercice " + exo.getNumber() + " : "
                  + unescapeHTML(exo.getTitle()) + ".</h1>\n");
            writer.write("\n");
            writer.write("        <div class=\"xo_contenu\">\n");
            writer.write("            <applet code=\"" + CHAPITRE + this.chapter.getNumber() 
                  + '.' + unescapeHTML(exo.getName()) 
                  + ".class\" codebase=\"http://sebastien-estienne.developpez.com/"
                  + "tutoriels/java/" + this.chapter.getName()
                  + "/fichiers/\" width=\"" + (int) this.appletDimension.get(i).getWidth()
                  + "\" height=\"" + (int) this.appletDimension.get(i).getHeight() + "\">\n");
            writer.write("                Votre navigateur n'est pas compatible Java.\n");
            writer.write("            </applet>\n");
            writer.write("        </div>\n");
            writer.write("\n");
            writer.write("        <p><a href=\"javascript:history.go(-1);\">Retour</a></p>\n");
            writer.write("        <p>&nbsp;</p>\n");
            writer.write("\n");
            writer.write("        <p id=\"infos_page\">Cette page est valide <a href=\"http://"
                  + "validator.w3.org/check?uri=referer\">XHTML 1.1</a> et <a href=\"http://"
                  + "jigsaw.w3.org/css-validator/check/referer\">CSS2</a></p>\n");
            writer.write("\n");
            writer.write("    </div>\n");
            writer.write("</div>\n");
            writer.write("\n");
            writer.write("<?\n");
            writer.write("    include(\"$DOCUMENT_ROOT/template/pied.php\");\n");
            writer.write("?>\n");
         }
         catch(IOException ioe)
         {
            ioe.printStackTrace();
         }
         finally
         {
            if(writer != null)
            {
               writer.close();
            }
         }
         i++;
      }
   }


   /**
    * <p>Converti les accents d'un chaine de caractères en code HTML.</p>
    * @param value La chaine de caractères à convertir.
    * @return Retourne une chaine de caractères avec des accents convertis en code HTML.
    */
   public static String unescapeHTML(String value)
   {
      String[][] asciiArray = { {"&lt;", "<"}, {"&gt;", ">"}, {"&amp;", "&"}, {"&quot;", "\""},
            {"&agrave;", "à"}, {"&Agrave;", "À"}, {"&acirc;", "â"}, {"&auml;", "ä"},
            {"&Auml;", "Ä"}, {"&Acirc;", "Â"}, {"&aring;", "å"}, {"&Aring;", "Å"},
            {"&aelig;", "æ"}, {"&AElig;", "Æ"}, {"&ccedil;", "ç"}, {"&Ccedil;", "Ç"},
            {"&eacute;", "é"}, {"&Eacute;", "É"}, {"&egrave;", "è"}, {"&Egrave;", "È"},
            {"&ecirc;", "ê"}, {"&Ecirc;", "Ê"}, {"&euml;", "ë"}, {"&Euml;", "Ë"}, {"&iuml;", "ï"},
            {"&Iuml;", "Ï"}, {"&ocirc;", "ô"}, {"&Ocirc;", "Ô"}, {"&ouml;", "ö"}, {"&Ouml;", "Ö"},
            {"&oslash;", "ø"}, {"&Oslash;", "Ø"}, {"&szlig;", "ß"}, {"&ugrave;", "ù"},
            {"&Ugrave;", "Ù"}, {"&ucirc;", "û"}, {"&Ucirc;", "Û"}, {"&uuml;", "ü"},
            {"&Uuml;", "Ü"}, {"&nbsp;", " "}, {"&reg;", "\u00a9"}, {"&copy;", "\u00ae"},
            {"&euro;", "\u20a0"}};

      int flag = -1;
      int ampIndex = -1;

      if(value.indexOf("&") >= 0)
      {
         if(value.indexOf(";") > value.indexOf("&"))
         {
            String asciiStuff = value.substring(value.indexOf("&"), value.indexOf(";") + 1);
            ampIndex = value.indexOf("&");
            while(asciiStuff.substring(1, asciiStuff.length()).indexOf("&") >= 0)
            {
               ampIndex = value.indexOf("&", ampIndex + 1);
               asciiStuff = asciiStuff.substring(1, asciiStuff.length()).trim();
            }
            for(int j = 0; j < asciiArray.length; j++)
            {
               if(asciiArray[j][0].equals(asciiStuff))
               {
                  flag = j;
                  break;
               }
            }
            if(flag >= 0)
            {
               value = value.substring(0, ampIndex) + asciiArray[flag][1]
                     + value.substring(value.indexOf(";") + 1, value.length());
               return unescapeHTML(value); // RECURSIVE
            }
         }
         return value;
      }

      return value.trim();
   }


   /**
    * <p>Lance l'application.</p>
    * @param args Les paramètres de la ligne de commande.
    */
   public static void main(String[] args)
   {
      if (args.length == 3)
      {
         // Chemin où se trouve le chapitre à XML à analyser.
         String chaperFilepath = args[0];
         
         // Chemin où se trouve les exercices en Java du chapitre.
         String exercisesPath = args[1];

         // Répertoire de sortie où les fichiers html seront produits.
         String outputPath = args[2];

         // Génération.
         new GenerateHtml(chaperFilepath, exercisesPath, outputPath);
      }

      System.exit(0);
   }

}
